using AutoMapper;
using Terra.Data.Entities.Identity;
using Terra.Data.Models.Identity;

namespace Terra.Service.Identity.Mappers;

/// <summary>
/// 身份管理模块对象映射配置
/// </summary>
public class IdentityMapperProfile : Profile
{
    /// <summary>
    /// 构造函数
    /// </summary>
    public IdentityMapperProfile()
    {
        #region 用户映射配置

        // User -> UserItemDto
        CreateMap<User, UserItemDto>()
            .ForMember(dest => dest.Roles, opt => opt.Ignore());

        // User -> UserDetailDto
        CreateMap<User, UserDetailDto>()
            .ForMember(dest => dest.Roles, opt => opt.Ignore())
            .ForMember(dest => dest.RoleIds, opt => opt.Ignore());

        // UserCreateDto -> User
        CreateMap<UserCreateDto, User>()
            .ForMember(dest => dest.Id, opt => opt.Ignore())
            .ForMember(dest => dest.UserRoles, opt => opt.Ignore())
            .ForMember(dest => dest.SecurityStamp, opt => opt.Ignore())
            .ForMember(dest => dest.NormalizedEmail, opt => opt.Ignore())
            .ForMember(dest => dest.NormalizedUserName, opt => opt.Ignore())
            .ForMember(dest => dest.EmailConfirmed, opt => opt.MapFrom(src => false))
            .ForMember(dest => dest.PhoneNumberConfirmed, opt => opt.MapFrom(src => false))
            .ForMember(dest => dest.TwoFactorEnabled, opt => opt.MapFrom(src => false))
            .ForMember(dest => dest.LockoutEnabled, opt => opt.MapFrom(src => true))
            .ForMember(dest => dest.AccessFailedCount, opt => opt.MapFrom(src => 0))
            .ForMember(dest => dest.CreatedTime, opt => opt.Ignore())
            .ForMember(dest => dest.LastModifiedTime, opt => opt.Ignore())
            .ForMember(dest => dest.DeletedTime, opt => opt.Ignore())
            .ForMember(dest => dest.IsDeleted, opt => opt.MapFrom(src => false))
            .ForMember(dest => dest.PasswordHash, opt => opt.Ignore())
            .ForMember(dest => dest.PasswordSalt, opt => opt.Ignore())
            .ForMember(dest => dest.LastPasswordChangedTime, opt => opt.Ignore());

        // UserUpdateDto -> User
        CreateMap<UserUpdateDto, User>()
            .ForMember(dest => dest.UserName, opt => opt.Ignore())
            .ForMember(dest => dest.NormalizedUserName, opt => opt.Ignore())
            .ForMember(dest => dest.NormalizedEmail, opt => opt.Ignore())
            .ForMember(dest => dest.EmailConfirmed, opt => opt.Ignore())
            .ForMember(dest => dest.PasswordHash, opt => opt.Ignore())
            .ForMember(dest => dest.PasswordSalt, opt => opt.Ignore())
            .ForMember(dest => dest.PhoneNumberConfirmed, opt => opt.Ignore())
            .ForMember(dest => dest.TwoFactorEnabled, opt => opt.Ignore())
            .ForMember(dest => dest.LockoutEnd, opt => opt.Ignore())
            .ForMember(dest => dest.LockoutEnabled, opt => opt.Ignore())
            .ForMember(dest => dest.AccessFailedCount, opt => opt.Ignore())
            .ForMember(dest => dest.SecurityStamp, opt => opt.Ignore())
            .ForMember(dest => dest.CreatedTime, opt => opt.Ignore())
            .ForMember(dest => dest.LastModifiedTime, opt => opt.MapFrom(src => DateTime.UtcNow))
            .ForMember(dest => dest.DeletedTime, opt => opt.Ignore())
            .ForMember(dest => dest.IsDeleted, opt => opt.Ignore())
            .ForMember(dest => dest.LastPasswordChangedTime, opt => opt.Ignore())
            .ForMember(dest => dest.UserRoles, opt => opt.Ignore());

        #endregion

        #region 角色映射配置
        // Role -> RoleItemDto
        CreateMap<Role, RoleItemDto>();

        // Role -> RoleDetailDto
        CreateMap<Role, RoleDetailDto>()
            .ForMember(dest => dest.CreatedTime, opt => opt.MapFrom(src => src.CreatedTime))
            .ForMember(dest => dest.LastModifiedTime, opt => opt.MapFrom(src => src.LastModifiedTime));

        // Role -> RoleSelectDto
        CreateMap<Role, RoleSelectDto>();

        // RoleCreateDto -> Role
        CreateMap<RoleCreateDto, Role>()
            .ForMember(dest => dest.Id, opt => opt.Ignore())
            .ForMember(dest => dest.NormalizedName, opt => opt.MapFrom(src => src.Name.ToUpper()))
            .ForMember(dest => dest.ConcurrencyStamp, opt => opt.MapFrom(src => Guid.NewGuid().ToString()))
            .ForMember(dest => dest.CreatedTime, opt => opt.Ignore())
            .ForMember(dest => dest.LastModifiedTime, opt => opt.Ignore())
            .ForMember(dest => dest.DeletedTime, opt => opt.Ignore())
            .ForMember(dest => dest.IsDeleted, opt => opt.MapFrom(src => false))
            .ForMember(dest => dest.UserRoles, opt => opt.Ignore());

        // RoleUpdateDto -> Role
        CreateMap<RoleUpdateDto, Role>()
            .ForMember(dest => dest.NormalizedName, opt => opt.MapFrom(src => src.Name.ToUpper()))
            .ForMember(dest => dest.CreatedTime, opt => opt.Ignore())
            .ForMember(dest => dest.LastModifiedTime, opt => opt.MapFrom(src => DateTime.UtcNow))
            .ForMember(dest => dest.DeletedTime, opt => opt.Ignore())
            .ForMember(dest => dest.IsDeleted, opt => opt.Ignore())
            .ForMember(dest => dest.IsSystem, opt => opt.Ignore())
            .ForMember(dest => dest.UserRoles, opt => opt.Ignore());
        #endregion

        #region 部门映射配置
        // 这里预留部门相关映射配置
        // 部门实体 -> 基础DTO
        CreateMap<Dept, DeptDto>();

        // 部门实体 -> 详情DTO
        CreateMap<Dept, DeptDetailDto>()
            .ForMember(dest => dest.ParentName, opt => opt.Ignore())
            .ForMember(dest => dest.LeaderName, opt => opt.Ignore())
            .ForMember(dest => dest.CreatedByName, opt => opt.Ignore())
            .ForMember(dest => dest.LastModifiedByName, opt => opt.Ignore());

        // 部门实体 -> 列表项DTO
        CreateMap<Dept, DeptItemDto>()
            .ForMember(dest => dest.ParentName, opt => opt.Ignore())
            .ForMember(dest => dest.LeaderName, opt => opt.Ignore());

        // 部门实体 -> 树形结构DTO
        CreateMap<Dept, DeptTreeDto>()
            .ForMember(dest => dest.Children, opt => opt.Ignore())
            .ForMember(dest => dest.IsLeaf, opt => opt.Ignore())
            .ForMember(dest => dest.Data, opt => opt.Ignore());

        // 部门实体 -> 下拉选择DTO
        CreateMap<Dept, DeptSelectDto>()
            .ForMember(dest => dest.Value, opt => opt.MapFrom(src => src.Id.ToString()))
            .ForMember(dest => dest.Label, opt => opt.MapFrom(src => src.Name))
            .ForMember(dest => dest.Disabled, opt => opt.MapFrom(src => src.Status == 0))
            .ForMember(dest => dest.Group, opt => opt.Ignore())
            .ForMember(dest => dest.Extra, opt => opt.Ignore());

        // 创建DTO -> 部门实体
        CreateMap<DeptCreateDto, Dept>()
            .ForMember(dest => dest.Id, opt => opt.Ignore())
            .ForMember(dest => dest.CreatedTime, opt => opt.Ignore())
            .ForMember(dest => dest.CreatedBy, opt => opt.Ignore())
            .ForMember(dest => dest.LastModifiedTime, opt => opt.Ignore())
            .ForMember(dest => dest.LastModifiedBy, opt => opt.Ignore())
            .ForMember(dest => dest.IsDeleted, opt => opt.MapFrom(src => false))
            .ForMember(dest => dest.DeletedTime, opt => opt.Ignore())
            .ForMember(dest => dest.DeletedBy, opt => opt.Ignore())
            .ForMember(dest => dest.Parent, opt => opt.Ignore())
            .ForMember(dest => dest.Children, opt => opt.Ignore())
            .ForMember(dest => dest.Users, opt => opt.Ignore());

        // 更新DTO -> 部门实体
        CreateMap<DeptUpdateDto, Dept>()
            .ForMember(dest => dest.CreatedTime, opt => opt.Ignore())
            .ForMember(dest => dest.CreatedBy, opt => opt.Ignore())
            .ForMember(dest => dest.LastModifiedTime, opt => opt.Ignore())
            .ForMember(dest => dest.LastModifiedBy, opt => opt.Ignore())
            .ForMember(dest => dest.IsDeleted, opt => opt.Ignore())
            .ForMember(dest => dest.DeletedTime, opt => opt.Ignore())
            .ForMember(dest => dest.DeletedBy, opt => opt.Ignore())
            .ForMember(dest => dest.Parent, opt => opt.Ignore())
            .ForMember(dest => dest.Children, opt => opt.Ignore())
            .ForMember(dest => dest.Users, opt => opt.Ignore());
        #endregion

        #region 菜单映射配置
        // 创建菜单元数据映射方法
        Action<Menu, MenuMetaDto> mapMenuMeta = (menu, meta) =>
        {
            if (meta != null)
            {
                menu.Title = meta.Title;
                menu.Icon = meta.Icon;
                menu.ActiveIcon = meta.ActiveIcon;
                menu.BadgeType = meta.BadgeType;
                menu.Badge = meta.Badge;
                menu.BadgeVariants = meta.BadgeVariants;
                menu.KeepAlive = meta.KeepAlive;
                menu.AffixTab = meta.AffixTab;
                menu.HideInMenu = meta.HideInMenu;
                menu.HideChildrenInMenu = meta.HideChildrenInMenu;
                menu.HideInBreadcrumb = meta.HideInBreadcrumb;
                menu.HideInTab = meta.HideInTab;

                // 根据菜单类型设置外链地址
                if (menu.Type == "embedded")
                    menu.LinkSrc = meta.IframeSrc;
                else if (menu.Type == "link")
                    menu.LinkSrc = meta.Link;
            }
        };

        // 创建Menu到MenuMetaDto的映射方法
        Func<Menu, MenuMetaDto> createMenuMetaDto = (src) => new MenuMetaDto
        {
            Title = src.Title,
            Icon = src.Icon,
            ActiveIcon = src.ActiveIcon,
            KeepAlive = src.KeepAlive,
            AffixTab = src.AffixTab,
            HideInMenu = src.HideInMenu,
            HideChildrenInMenu = src.HideChildrenInMenu,
            HideInBreadcrumb = src.HideInBreadcrumb,
            HideInTab = src.HideInTab,
            BadgeType = src.BadgeType,
            Badge = src.Badge,
            BadgeVariants = src.BadgeVariants,
            IframeSrc = src.Type == "embedded" ? src.LinkSrc : null,
            Link = src.Type == "link" ? src.LinkSrc : null
        };

        // 菜单实体 -> 基础DTO
        CreateMap<Menu, MenuDto>()
            .ForMember(dest => dest.Meta, opt => opt.MapFrom(src => createMenuMetaDto(src)));

        // 菜单实体 -> 详情DTO
        CreateMap<Menu, MenuDetailDto>()
            .ForMember(dest => dest.Meta, opt => opt.MapFrom(src => createMenuMetaDto(src)));

        // 菜单实体 -> 列表项DTO
        CreateMap<Menu, MenuItemDto>()
            .ForMember(dest => dest.Meta, opt => opt.MapFrom(src => createMenuMetaDto(src)));

        // 菜单实体 -> 树节点DTO
        CreateMap<Menu, MenuTreeDto>()
            .ForMember(dest => dest.Children, opt => opt.Ignore())
            
            .ForMember(dest => dest.PermissionId, opt =>
                opt.MapFrom(src => src.Permission != null ? src.Permission.Id : (Guid?)null))
            .ForMember(dest => dest.Meta, opt => opt.MapFrom(src => createMenuMetaDto(src)));

        // 菜单实体 -> 选择DTO
        CreateMap<Menu, MenuSelectDto>();

        // 菜单实体 -> 前端路由DTO
        CreateMap<Menu, RouterMenuDto>()
            .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Name))
            .ForMember(dest => dest.Path, opt => opt.MapFrom(src => src.Path))
            .ForMember(dest => dest.Component, opt => opt.MapFrom(src => src.Component))
            .ForMember(dest => dest.Redirect, opt => opt.MapFrom(src =>
                src.Type == "catalog" && !string.IsNullOrEmpty(src.Path) ? $"{src.Path}/index" : null))
            .ForMember(dest => dest.Meta, opt => opt.MapFrom(src => createMenuMetaDto(src)))
            .ForMember(dest => dest.Children, opt => opt.Ignore());

        // 创建DTO -> 菜单实体
        CreateMap<MenuCreateDto, Menu>()
            .AfterMap((src, dest) => mapMenuMeta(dest, src.Meta));

        // 更新DTO -> 菜单实体
        CreateMap<MenuUpdateDto, Menu>()
            .ForMember(dest => dest.Id, opt => opt.Ignore())
            .AfterMap((src, dest) => mapMenuMeta(dest, src.Meta));
        
        #endregion
    }
}
